
using System;
using System.Collections.Generic;
using System.IO;
using ScrewTurn.Wiki.PluginFramework;

namespace ScrewTurn.Wiki {

	/// <summary>
	/// Contains the WikiMarkup Snippets.
	/// </summary>
	public class Snippets {

		private List<Snippet> snippets;

		private static Snippets instance;

		/// <summary>
		/// Gets or sets the Singleton instance of the Snippets object.
		/// </summary>
		public static Snippets Instance {
			get {
				if(instance == null) throw new InvalidOperationException("Snippets.Instance is null");
				return instance;
			}
			set { instance = value; }
		}

		/// <summary>
		/// Initializes a new instance of the <b>Snippets</b> class.
		/// </summary>
		public Snippets() {
			snippets = new List<Snippet>();
			Load();
		}

		/// <summary>
		/// Gets the complete list of the Snippets.
		/// </summary>
		public List<Snippet> AllSnippets {
			get { return snippets; }
		}

		/// <summary>
		/// Loads the Snippets.
		/// </summary>
		private void Load() {
			lock(snippets) {
				snippets.Clear();
				for(int i = 0; i < Collectors.PagesProviderCollector.AllProviders.Length; i++) {
					LoadFrom(Collectors.PagesProviderCollector.AllProviders[i], false);
				}
				snippets.Sort(new SnippetNameComparer());
			}
		}

		/// <summary>
		/// Loads the Snippets from a Provider.
		/// </summary>
		/// <param name="provider">The Provider.</param>
		/// <param name="autoSort">True to autosort the list.</param>
		public void LoadFrom(IPagesStorageProvider provider, bool autoSort) {
			snippets.AddRange(provider.AllSnippets);
			if(autoSort) snippets.Sort(new SnippetNameComparer());
		}

		/// <summary>
		/// Reloads the Snippets from a Provider.
		/// </summary>
		/// <param name="provider">The Provider.</param>
		/// <param name="autoSort">True to autosort the list.</param>
		public void ReloadFrom(IPagesStorageProvider provider, bool autoSort) {
			UnloadFrom(provider);
			LoadFrom(provider, autoSort);
		}

		/// <summary>
		/// Unloads the Snippets managed by a Provider.
		/// </summary>
		/// <param name="provider">The Provider.</param>
		public void UnloadFrom(IPagesStorageProvider provider) {
			List<Snippet> toRemove = new List<Snippet>();
			for(int i = 0; i < snippets.Count; i++) {
				if(snippets[i].Provider == provider) toRemove.Add(snippets[i]);
			}
			for(int i = 0; i < toRemove.Count; i++) {
				snippets.Remove(toRemove[i]);
			}
		}

		/// <summary>
		/// Finds a Snippet.
		/// </summary>
		/// <param name="name">The Name of the Snippet to find.</param>
		/// <returns>The Snippet or null if it is not found.</returns>
		public Snippet Find(string name) {
			lock(snippets) {
				int result = snippets.BinarySearch(new Snippet(name, "", null), new SnippetNameComparer());
				if(result >= 0) return snippets[result];
				else return null;
			}
		}

		/// <summary>
		/// Creates a new Snippet.
		/// </summary>
		/// <param name="name">The name of the Snippet.</param>
		/// <param name="content">The content of the Snippet.</param>
		/// <param name="provider">The Provider to use to store the Snippet.</param>
		/// <returns>True if the Snippets has been addedd successfully.</returns>
		public bool AddSnippet(string name, string content, IPagesStorageProvider provider) {
			if(Find(name) != null) return false;

			if(provider == null) provider = Collectors.PagesProviderCollector.GetProvider(Settings.DefaultPagesProvider);

			Snippet newSnippet = provider.AddSnippet(name, content);

			if(newSnippet != null) {
				lock(snippets) {
					snippets.Add(newSnippet);
					snippets.Sort(new SnippetNameComparer());
				}
				Log.LogEntry("Snippet " + name + " created", EntryType.General, "SYSTEM");
			}
			else Log.LogEntry("Creation failed for Snippet " + name, EntryType.Error, "SYSTEM");

			return newSnippet != null;
		}

		/// <summary>
		/// Removes a Snippet.
		/// </summary>
		/// <param name="snippet">The Snippet to remove.</param>
		/// <returns>True if the Snippet has been removed successfully.</returns>
		public bool RemoveSnippet(Snippet snippet) {
			bool done = snippet.Provider.RemoveSnippet(snippet.Name);
			if(done) {
				lock(snippets) {
					snippets.Remove(snippet);
				}
				Log.LogEntry("Snippet " + snippet.Name + " deleted", EntryType.General, "SYSTEM");
			}
			else Log.LogEntry("Deletion failed for Snippet " + snippet.Name, EntryType.Error, "SYSTEM");

			return done;
		}

		/// <summary>
		/// Modifies the Content of a Snippet.
		/// </summary>
		/// <param name="snippet">The Snippet to update.</param>
		/// <param name="content">The new Content.</param>
		/// <returns>True if the Snippet has been updated successfully.</returns>
		public bool ModifySnippet(Snippet snippet, string content) {
			Snippet newSnippet = snippet.Provider.ModifySnippet(snippet.Name, content);
			if(newSnippet != null) {
				lock(snippets) {
					snippets.Remove(snippet);
					snippets.Add(newSnippet);
					snippets.Sort(new SnippetNameComparer());
				}
				Log.LogEntry("Snippet " + snippet.Name + " updated", EntryType.General, "SYSTEM");
			}
			else Log.LogEntry("Modification failed for Snippet " + snippet.Name, EntryType.Error, "SYSTEM");

			return newSnippet != null;
		}

	}

}
